import pymysql
from pymysql.cursors import DictCursor


class Mysql_Option:
    def __init__(self, host, port, user, password, database=None, charset='utf8'):
        """
        mysql的连接操作类
        :param host: 连接地址
        :param port: 连接端口
        :param user: mysql用户名
        :param password: mysql密码
        :param database: 连接数据库，默认None
        :param charset: mysql的字符编码
        """
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.charset = charset
        self.autocommit = True

        self.connect()

    def connect(self):
        """
        连接方法
        :return:是否连接成功
        """
        try:
            self.conn = pymysql.connect(host=self.host,
                                        port=self.port,
                                        user=self.user,
                                        password=self.password,
                                        database=self.database,
                                        charset=self.charset,
                                        autocommit=self.autocommit)
            self.cursor = self.conn.cursor(cursor=DictCursor)
            return True
        except Exception as e:
            print(f"连接{self.host}失败，请查看：{e}")
            self.cursor = None
            self.conn = None
            return False

    def __del__(self):
        self.close()

    def close(self):
        """
        关闭mysql连接
        :return:
        """
        if self.cursor:
            self.cursor.close()
            print("关闭mysql_cursor")
        if self.conn:
            self.conn.close()
            print("关闭mysql_conn")

    def _execute(self, sql):
        """
        内部执行SQL语句的方法，并处理异常
        :param sql: 要执行的SQL语句
        :return: 执行结果或None（如果执行失败）
        """
        try:
            self.cursor.execute(sql)
            return self.cursor.fetchall()
        except Exception as e:
            print(f"执行<{sql}>语句失败！，请查看：{e}")
            self.conn.rollback()
            return None

    # 列出所有的databases
    def list_all_databases(self):
        """
        列出mysql中的所有databases
        :return: 数据库列表
        """
        sql = "SHOW DATABASES;"
        return [row["Database"] for row in self._execute(sql)]

    # 列出所有的tables
    def list_all_tables(self, database=None):
        """
        列出指定数据库中的所有的tables
        :param database: 如需指定其他数据库，就填写名称，如不指定，就不用填
        :return: tables列表
        """
        if database is None:
            sql = "SHOW TABLES;"
        else:
            self._execute(f"USE {database};")
            sql = "SHOW TABLES;"
        return [row[f"Tables_in_{database or self.database}"] for row in self._execute(sql)]

    # 创建数据库
    def create_database(self, database):
        """
        创建数据库
        :param database: 数据库的名称
        :return: 是否成功创建
        """
        sql = f"CREATE DATABASE IF NOT EXISTS {database} DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci;"
        return self._execute(sql) is not None

    # 删除数据库
    def remove_database(self, database):
        """
        删除数据库
        :param database: 数据库名称
        :return: 是否成功删除
        """
        sql = f"DROP DATABASE IF EXISTS {database};"
        return self._execute(sql) is not None

    # 创建表
    def create_table(self, table_name, kwargs):
        """
        创建表
        :param table_name: 新表名
        :param kwargs: 表中参数，字典类型{"p":"int"}
        :return: 是否成功创建
        """
        column_definitions = [f"{key} {value}" for key, value in kwargs.items() if key != 'table_name']
        sql = f"CREATE TABLE IF NOT EXISTS {table_name} ({', '.join(column_definitions)}) DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci;"
        return self._execute(sql) is not None

    # 删除指定table
    def remove_table(self, table_name):
        """
        删除指定表
        :param table_name: 表名
        :return: 是否成功删除
        """
        sql = f"DROP TABLE IF EXISTS {table_name};"
        return self._execute(sql) is not None

    # 在指定table中插入值
    def insert_table_values(self, table_name, data: dict):
        """
        在指定表中插入指定的值
        :param table_name: 表名
        :param data: 插入的数据，字典类型{"p":"int"}
        :return: 是否成功插入
        """
        keys = tuple(data.keys())
        values = tuple(data.values())
        key_str = ', '.join(keys)
        value_str = ', '.join([repr(value) for value in values])
        sql = f"INSERT INTO {table_name} ({key_str}) VALUES ({value_str});"
        return self._execute(sql) is not None

    # 在指定的table中删除行值
    def delete_table_values(self, table_name, where: dict = None, order_by_name=None, order_by: bool = True,
                            limit: int = None):
        """
        在指定的表中删除指定的行
        :param table_name: 表名
        :param where: 筛选条件，字典类型{"p":"int"}
        :param order_by_name: 排序列名称
        :param order_by: 升序/降序,True是升序，False是降序
        :param limit: 限制多少条数据
        :return: 是否成功删除
        """
        sql = f"DELETE FROM {table_name}"
        if where:
            conditions = [f"{key} = '{value}'" for key, value in where.items()]
            sql += f" WHERE {' AND '.join(conditions)}"
        if order_by_name:
            sql += f" ORDER BY {order_by_name} {'ASC' if order_by else 'DESC'}"
        if limit:
            sql += f" LIMIT {limit}"
        sql += ";"
        return self._execute(sql) is not None

    # 在指定table中更新指定的行的某个值
    def update_table_values(self, table_name, new_data: dict, where: dict):
        """
        在指定的表中更新指定行的指定值
        :param table_name: 表名
        :param new_data: 更新的新数据，字典类型{"p":"int"}
        :param where: 筛选条件，字典类型{"p":"int"}
        :return: 是否成功更新
        """
        sql = f"UPDATE {table_name} SET "
        conditions = [f"{key} = '{value}'" for key, value in new_data.items()]
        sql += ', '.join(conditions)
        where_conditions = [f"{key} = '{value}'" for key, value in where.items()]
        sql += f" WHERE {' AND '.join(where_conditions)}"
        sql += ";"
        return self._execute(sql) is not None

    # 在指定table中插入值,REPLACE语法
    def replace_table_values(self, table_name, data: dict):
        """
        插入替换某个表中的所有值，注意是插入的替换用法，必须保证有唯一键，才能找到
        :param table_name: 表名
        :param data: 插入的数据，字典类型{"p":"int"}
        :return: 是否成功插入
        """
        keys = tuple(data.keys())
        values = tuple(data.values())
        key_str = ', '.join(keys)
        value_str = ', '.join([repr(value) for value in values])
        sql = f"REPLACE INTO {table_name} ({key_str}) VALUES ({value_str});"
        return self._execute(sql) is not None

    # 查询表数据
    def query_table_data(self, table_name, where: dict = None, order_by_name=None, order_by: bool = True,
                         limit: int = None):
        """
        查询表数据
        :param table_name: 表名
        :param where: 筛选条件，字典类型{"p":"int"}
        :param order_by_name: 排序列名称
        :param order_by: 升序/降序,True是升序，False是降序
        :param limit: 限制多少条数据
        :return: 查询返回的数据
        """
        sql = f"SELECT * FROM {table_name}"
        if where:
            conditions = [f"{key} = '{value}'" for key, value in where.items()]
            sql += f" WHERE {' AND '.join(conditions)}"
        if order_by_name:
            sql += f" ORDER BY {order_by_name} {'ASC' if order_by else 'DESC'}"
        if limit:
            sql += f" LIMIT {limit}"
        sql += ";"
        return self._execute(sql)

    # 获取列名
    def get_column_names(self, table_name):
        """
        获取指定表的列名
        :param table_name: 表名
        :return: 列名数据列表
        """
        sql = f"DESCRIBE {table_name};"
        results = self._execute(sql)
        return [row['Field'] for row in results]

    # 添加列
    def add_column(self, table_name, column_name, data_type):
        """
        在指定表中添加列
        :param table_name: 表名
        :param column_name: 列名
        :param data_type: 列的类型
        :return: 是否添加成功
        """
        if column_name not in self.get_column_names(table_name):
            sql = f"ALTER TABLE {table_name} ADD {column_name} {data_type};"
            return self._execute(sql) is not None
        else:
            print(f"{column_name}已存在，不需要添加！")
            return False

    # 删除列
    def remove_column(self, table_name, column_name):
        """
        在指定表中删除指定列
        :param table_name: 表名
        :param column_name: 列名
        :return: 是否成功删除
        """
        if column_name in self.get_column_names(table_name):
            sql = f"ALTER TABLE {table_name} DROP COLUMN {column_name};"
            return self._execute(sql) is not None
        else:
            print(f"{column_name}不存在，不需要删除！")
            return False

    # 修改列名
    def modify_column(self, table_name, old_column_name, new_column_name, new_data_type=None):
        """
        在指定表中修改列名
        :param table_name: 表名
        :param old_column_name: 旧的列名
        :param new_column_name: 新列名
        :param new_data_type: 新列的类型，如果为None则继承原列类型
        :return: 是否成功修改
        """
        if old_column_name in self.get_column_names(table_name):
            if new_data_type is None:
                sql = f"ALTER TABLE {table_name} CHANGE {old_column_name} {new_column_name} {old_column_name};"
            else:
                sql = f"ALTER TABLE {table_name} CHANGE {old_column_name} {new_column_name} {new_data_type};"
            return self._execute(sql) is not None
        else:
            print(f"列名{old_column_name}不存在，不需要修改！")
            return False

    # 修改表名
    def modify_table_name(self, old_table_name, new_table_name):
        """
        修改表名
        :param old_table_name: 旧表名
        :param new_table_name: 新表名
        :return: 是否成功修改
        """
        if old_table_name in self.list_all_tables() and new_table_name not in self.list_all_tables():
            sql = f"RENAME TABLE {old_table_name} TO {new_table_name};"
            return self._execute(sql) is not None
        elif old_table_name in self.list_all_tables() and new_table_name in self.list_all_tables():
            print(f"表名{new_table_name}已经存在，不能修改！")
            return False
        else:
            print(f"表名{old_table_name}不存在，不能修改！")
            return False

    # 复制表名（不包含数据）
    def copy_table(self, old_table_name, new_table_name):
        """
        复制表名，创建新表（不包含数据）
        :param old_table_name: 旧表名
        :param new_table_name: 新表名
        :return: 是否成功复制
        """
        if old_table_name in self.list_all_tables() and new_table_name not in self.list_all_tables():
            sql = f"CREATE TABLE {new_table_name} LIKE {old_table_name};"
            return self._execute(sql) is not None
        elif old_table_name in self.list_all_tables() and new_table_name in self.list_all_tables():
            print(f"表名{new_table_name}已经存在，不能复制！")
            return False
        else:
            print(f"表名{old_table_name}不存在，不能复制！")
            return False

    # 复制表名（包含数据）
    def copy_table_with_data(self, old_table_name, new_table_name):
        """
        复制表名，创建新表（包含数据）
        :param old_table_name: 旧表名
        :param new_table_name: 新表名
        :return: 是否成功复制
        """
        if old_table_name in self.list_all_tables() and new_table_name not in self.list_all_tables():
            sql = f"CREATE TABLE {new_table_name} AS SELECT * FROM {old_table_name};"
            return self._execute(sql) is not None
        elif old_table_name in self.list_all_tables() and new_table_name in self.list_all_tables():
            print(f"表名{new_table_name}已经存在，不能复制！")
            return False
        else:
            print(f"表名{old_table_name}不存在，不能复制！")
            return False
